package Products;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;

import Exceptions.CantRemoveException;
import Exceptions.ProductNeverPurchasedException;
import Exceptions.ProductSalesPriceNeverSetException;
import Magnitudes.Litre;
import Magnitudes.Percentage;


public class ProductTest extends TestCase {
	
	Litre twoLitres = mock(Litre.class);
	Presentation oneAndAQuarterLitres = mock(Presentation.class);
	Presentation footwearPresentation = mock(Presentation.class);
	Presentation anotherFootwearPresentation = mock(Presentation.class);
	Presentation clothePresentation = mock(Presentation.class);
	Foodstuff foodstuff = mock(Foodstuff.class);
	FootWear footwear = mock(FootWear.class);
	Clothe clothe = mock(Clothe.class);
	Product productCreatingPresentationToTest;
	Product productWithPresentationToTest;
	Product footwearProduct;
	Product clotheProduct;
	Percentage percentage = mock(Percentage.class);
	
	@Before
	public void setUp(){
		when(foodstuff.isFoodstuff()).thenReturn(true);
		productCreatingPresentationToTest = 
				new Product("Coca-Cola", "Bebida sin alcohol gasificada de extractos vegetales", 
						"The Coca-Cola Company", foodstuff, twoLitres, "123");
		
		productWithPresentationToTest = 
				new Product("Sprite", "Bebida sin alcohol gasificada de extractos vegetales", 
						"The Coca-Cola Company", foodstuff,  oneAndAQuarterLitres);
		
		footwearProduct = new Product("Airmax 2014", "Zapatillas para correr", "Nike", footwear, footwearPresentation);
		clotheProduct = new Product("DryFit Jacket", "Campera liviana", "Nike", clothe, clothePresentation);
				
	}
	
// Falta verificar que dentro del constructor se llamo a ambos addANewPresentation una vez por cada caso
	
	@Test
	public void testGivenACreatedProductWhenAskForPresentationsWhouldHaveAtLeastOne(){
		assertTrue(productCreatingPresentationToTest.getPresentations().size()>0);
		assertTrue(productWithPresentationToTest.getPresentations().size()>0);
		assertTrue(footwearProduct.getPresentations().size()>0);
		assertTrue(clotheProduct.getPresentations().size()>0);
	}
	
	@Test
	public void testGivenACreatedProductWithASinglePresentationWhenAddANewPresentationWithAPresentationShouldHaveTwo(){
		productCreatingPresentationToTest.addANewPresentation(oneAndAQuarterLitres);
		assertTrue(productCreatingPresentationToTest.getPresentations().size() == 2);
	}
	
	@Test
	public void testGivenACreatedProductWithASinglePresentationWhenAddANewPresentationWithParamsToCreateAPresentationShouldHaveTwo(){
		productWithPresentationToTest.addANewPresentation(twoLitres, "123");
		assertTrue(productWithPresentationToTest.getPresentations().size() == 2);
	}
	
	@Test
	public void testGivenAFoodstuffWhenAskIsFoodstuffShouldReturnTrue(){
		assertTrue(productWithPresentationToTest.isFoodstuff());
		assertTrue(productCreatingPresentationToTest.isFoodstuff());
	}
	
	@Test
	public void testGivenAFoodstuffWhenAskIsClotheShouldReturnFalse(){
		assertFalse(productWithPresentationToTest.isClothe());
		assertFalse(productCreatingPresentationToTest.isClothe());
	}
	
	@Test
	public void testGivenAFoodstuffWhenAskIsFootwearShouldReturnFalse(){
		assertFalse(productWithPresentationToTest.isFootwear());
		assertFalse(productCreatingPresentationToTest.isFootwear());
	}
	
	@Test
	public void testGivenAFootwearWhenAskIsFootwearShouldReturnTrue(){
		when(footwear.isFootwear()).thenReturn(true);		
		assertTrue(footwearProduct.isFootwear());
		//assertTrue(footwearProduct.isFootwear());
	}
	
	@Test
	public void testGivenAFootwearWhenAskIsFoodstuffShouldReturnFalse(){
		assertFalse(footwearProduct.isFoodstuff());
	}
	
	@Test
	public void testGivenAFootwearWhenAskIsClotheShouldReturnFalse(){		
		assertFalse(footwearProduct.isClothe());
	}
	
	@Test
	public void testGivenAClotheWhenAskIsClotheShouldReturnTrue(){
		when(clothe.isClothe()).thenReturn(true);
		assertTrue(clotheProduct.isClothe());
	}
	
	@Test
	public void testGivenAClotheWhenAskIsFoodstuffShouldReturnFalse(){
		assertFalse(clotheProduct.isFoodstuff());
	}
	
	@Test
	public void testGivenAClotheWhenAskIsFootwearShouldReturnFalse(){
		assertFalse(clotheProduct.isFootwear());
	}
	
	@Test
	public void testGivenACreatedProductWithTwoPresentationsWhenRemovePresentationShouldHaveASinglePresentation(){
		productCreatingPresentationToTest.addANewPresentation(oneAndAQuarterLitres);
		assertTrue(productCreatingPresentationToTest.getPresentations().size() == 2);
		try {
			productCreatingPresentationToTest.removePresentation(oneAndAQuarterLitres);
		} catch (CantRemoveException e) {
			e.printStackTrace();
		}
		assertTrue(productCreatingPresentationToTest.getPresentations().size() == 1);
	}
	
	@Test
	public void testGivenACreatedProductWithASinglePresentationWhenRemovePresentationShouldThrowACantRemoveException(){
		assertTrue(clotheProduct.getPresentations().size() == 1);
		Exception exception = null;
		try {
			clotheProduct.removePresentation(clothePresentation);
		} catch (CantRemoveException cantRemoveException) {
			exception = cantRemoveException;
		}		
		assertNotNull(exception);
		assertTrue(exception.getMessage().contains("Can't remove presentation"));
	}
	
	
	@Test
	public void testGivenAProductWithTwoPresentationsWhenRemovePresentationThatIsntThereShouldThrowInvalidRemotionException(){
		Exception exception = null;
	
		try{
			productCreatingPresentationToTest.removePresentation(clothePresentation);
		} catch (CantRemoveException invalidRemotionException){
			exception = invalidRemotionException;
		}				
		assertNotNull(exception);
		assertTrue(exception.getMessage().contains("Can't remove presentation"));
	}	
	
	
	@Test
	public void testGivenACreatedProductWithASinglePresentationWhenUpdatePurchasePriceShouldSendASingleMessageToThePresentation(){
		footwearProduct.updateUnitPurchasePriceBy(percentage);
		try {
			verify(footwearPresentation, times(1)).updateUnitPurchasePriceBy(percentage);
		} catch (ProductNeverPurchasedException e) {
			e.printStackTrace();
		}
	}
	
	
	@Test
	public void testGivenACreatedProductWithTwoPresentationsWhenUpdatePurchasePriceShouldSendTwoMessageForEachPresentation(){
		footwearProduct.addANewPresentation(anotherFootwearPresentation);
		footwearProduct.updateUnitPurchasePriceBy(percentage);
		try {
			verify(footwearPresentation, times(1)).updateUnitPurchasePriceBy(percentage);
		} catch (ProductNeverPurchasedException e) {
			e.printStackTrace();
		}
		try {
			verify(anotherFootwearPresentation, times(1)).updateUnitPurchasePriceBy(percentage);
		} catch (ProductNeverPurchasedException e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testGivenACreatedProductWithASinglePresentationWhenUpdatePurchasePriceNUpdateSalesPriceShouldSendASingleMessageToThePresentation(){
		footwearProduct.updateUnitPurchasePriceByAndUpdateSalesPrice(percentage, percentage);
		try {
			verify(footwearPresentation, times(1)).updateUnitPurchasePriceByAndUpdateSalesPrice(percentage, percentage);
		} catch (ProductNeverPurchasedException e) {
			e.printStackTrace();
		} catch (ProductSalesPriceNeverSetException e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testGivenACreatedProductWithTwoPresentationsWhenUpdatePurchasePriceNUpdateSalesPriceShouldSendTwoMessageForEachPresentation(){
		footwearProduct.addANewPresentation(anotherFootwearPresentation);
		footwearProduct.updateUnitPurchasePriceByAndUpdateSalesPrice(percentage, percentage);
		try {
			verify(footwearPresentation, times(1)).updateUnitPurchasePriceByAndUpdateSalesPrice(percentage, percentage);
		} catch (ProductNeverPurchasedException e) {
			e.printStackTrace();
		} catch (ProductSalesPriceNeverSetException e) {
			e.printStackTrace();
		}
		try {
			verify(anotherFootwearPresentation, times(1)).updateUnitPurchasePriceByAndUpdateSalesPrice(percentage, percentage);
		} catch (ProductNeverPurchasedException e) {
			e.printStackTrace();
		} catch (ProductSalesPriceNeverSetException e) {
			e.printStackTrace();
		}
	}
	
}
